var stats = new Stats(),
    sds = stats.domElement.style;
sds.position = 'absolute';
sds.top = '0px';
sds.right = '0px';
document.body.appendChild(stats.domElement);

var c = document.getElementById('c'),
    ctx = c.getContext('2d'),
    gameAreaAbsoluteWidth, gameAreaAbsoluteHeight, gameAreaOffsetWidth, gameAreaOffsetHeight, //游戏区的绝对宽度和偏移量
    //常量配置
    setting = {
        gameAreaWidth: .8, //游戏区宽度占总宽的百分比
        gameAreaHeight: .8 //游戏区高度占总高的百分比
    },
    //按键状态记录
    keyPressed = {},
    //发球方向，false向左，true向右
    serveParty = true,
    ball = null;

//处理屏幕大小
window.addEventListener('resize', handleResize, false);
function handleResize() {
    c.width = window.innerWidth * window.devicePixelRatio;
    c.height = window.innerHeight * window.devicePixelRatio;
    gameAreaAbsoluteWidth = c.width * setting.gameAreaWidth;
    gameAreaAbsoluteHeight = c.height * setting.gameAreaHeight;
    gameAreaOffsetWidth = (c.width - gameAreaAbsoluteWidth) / 2;
    gameAreaOffsetHeight = (c.height - gameAreaAbsoluteHeight) / 2;
}
handleResize();

/* ================================================================ */
/* 玩家类 */
/* ================================================================ */
/**
 * 玩家类构造函数
 * @param {Number} x 挡板初始位置 
 * @param {Number} y 挡板初始位置 
 * @param {Number} height 挡板默认高度
 * @param {枚举Number} pNum 可选值1， 2
 */
function Player(x, y, height, pNum) {
    this.x = x || 0;
    this.y = y || 0;
    if(pNum === 1 || pNum === 2) {
        this.pNum = pNum;
    } else {
        throw new Error('第四参数pNum必须为数字1或2');
    }
    this.width = 30; //挡板宽度
    this.height = height || 100; //挡板高度
    this.loseAreaWidth = 50; //失分区宽度
    this.points = 0; //得分
    this.speed = 10;
}
Player.prototype = (function(o){
    var s = {}, p;
    for(p in o) s[p] = o[p];
    return s;
})({
    //加分函数
    addPoint: function() {
        this.points++;
    },
    update: function(param) {
        if(param > 0) {
            this.y += this.speed;
        } else {
            this.y -= this.speed;
        }
        //判断是否已到边界
        if(this.y <= gameAreaOffsetHeight) {
            this.y = gameAreaOffsetHeight;
        } else if (this.y >= gameAreaOffsetHeight + gameAreaAbsoluteHeight - this.height) {
            this.y = gameAreaOffsetHeight + gameAreaAbsoluteHeight - this.height;
        }
    },
    //绘制图形
    draw: function(ctx) {
        //绘制失分区
        this.drawLosePointArea(ctx);
        //绘制挡板
        this.drawBaffle(ctx);
    },
    //绘制失分区函数
    drawLosePointArea: function(ctx) {
        ctx.save();
        ctx.fillStyle = 'rgba(127, 127, 127, .75)';
        if(this.pNum === 1) {
            ctx.fillRect(gameAreaOffsetWidth, gameAreaOffsetHeight, this.loseAreaWidth, gameAreaAbsoluteHeight);
        } else {
            ctx.fillRect(gameAreaOffsetWidth + gameAreaAbsoluteWidth - this.loseAreaWidth, gameAreaOffsetHeight, this.loseAreaWidth, gameAreaAbsoluteHeight);
        }
        ctx.restore();
    },
    //绘制挡板
    drawBaffle: function(ctx) {
        ctx.save();
        ctx.fillStyle = '#fff';
        ctx.fillRect(this.x, this.y, this.width, this.height);
        ctx.restore();
    }
})

/* ================================================================ */
/* 球类 */
/* ================================================================ */
/**
 * 球类的构造函数
 * @param {Number} x 横坐标
 * @param {Number} y 纵坐标
 * @param {Number} speed 绝对速度
 * @param {Number} rotate 方向
 */
function Ball(x, y, speed, rotate) {
    Vector.call(this, x, y);
    this.speed = new Vector();
    this.radius = 15;
    this.angleRange = [
        180 / Math.PI * (Math.atan2(gameAreaOffsetHeight + gameAreaAbsoluteHeight - c.height / 2, gameAreaOffsetWidth + gameAreaAbsoluteWidth - c.width / 2)),
        180 / Math.PI * (Math.atan2(gameAreaOffsetHeight + gameAreaAbsoluteHeight - c.height / 2, gameAreaOffsetWidth - c.width / 2))
    ];
}
Ball.reBuildBall = function() {
    ball = null;
    serveParty = !serveParty;
    //构建球实例
    ball = new Ball(c.width / 2, c.height / 2, 10, 0);
    var ballSpeedValue = 10;
    var angle = (function(){
        var result = 0;
        if(serveParty) { //向右
            result = Math.random() * 2 * ball.angleRange[0] - ball.angleRange[0];
        } else { //向左
            if(Math.random() > .5) { //到-180
                result = Math.random() * (-180 + ball.angleRange[1]) - ball.angleRange[1];
            } else { //到180
                result = Math.random() * (180 - ball.angleRange[1]) + ball.angleRange[1];
            }
        }
        return result;
    })()
    ball.speed.set(Math.cos(angle * Math.PI / 180) * ballSpeedValue, Math.sin(angle * Math.PI / 180) * ballSpeedValue);
};
Ball.prototype = (function(o){
    var s = new Vector(0, 0), p;
    for(p in o) s[p] = o[p];
    return s;
})({
    //更新
    update: function(ctx, p1, p2) {
        this.add(this.speed);
        if(this.y - this.radius <= gameAreaOffsetHeight || this.y + this.radius >= gameAreaOffsetHeight + gameAreaAbsoluteHeight) {
            this.speed.y *= -1;
        }
        this.hitTestP1(p1);
        this.hitTestP2(p2);
        this.hitTestP1LostPointArea(p1, p2);
        this.hitTestP2LostPointArea(p1, p2);
        this.draw(ctx);
    },
    //绘制图形
    draw: function(ctx) {
        ctx.save();
        ctx.fillStyle = '#fff';
        ctx.translate(this.x, this.y);
        ctx.beginPath();
        ctx.arc(0, 0, this.radius, 0, Math.PI * 2, false);
        ctx.closePath();
        ctx.fill();
        ctx.restore();
    },
    //与p1挡板的碰撞检测
    hitTestP1: function(p) {
        if(this.y >= p.y && this.y <= p.y + p.height && this.x - this.radius <= p.x + p.width) {
            this.speed.x *= -1;
        }
    },
    //与p2挡板的碰撞
    hitTestP2: function(p) {
        if(this.y >= p.y && this.y <= p.y + p.height && this.x + this.radius >= p.x) {
            this.speed.x *= -1;
        }
    },
    //与p1失分区碰撞检测
    hitTestP1LostPointArea: function(p1, p2) {
        if(this.x - this.radius <= gameAreaOffsetWidth + p1.loseAreaWidth) {
            Ball.reBuildBall();
            p2.points++;
        }
    },
    //与p2失分区碰撞检测
    hitTestP2LostPointArea: function(p1, p2) {
        if(this.x + this.radius >= gameAreaOffsetWidth + gameAreaAbsoluteWidth - p2.loseAreaWidth) {
            Ball.reBuildBall();
            p1.points++;
        }
    }
})

//构建p1、p2两个玩家实例
var p1 = new Player(gameAreaOffsetWidth + 80, gameAreaOffsetHeight + gameAreaAbsoluteHeight / 2 - 50, 100, 1);
var p2 = new Player(gameAreaOffsetWidth + gameAreaAbsoluteWidth - 110, gameAreaOffsetHeight + gameAreaAbsoluteHeight / 2 - 50, 100, 2);
//绑定事件处理函数
document.addEventListener('keyup', function(e) {
    var event = e || window.event;
    if(event.keyCode === 38 || event.keyCode === 40 || event.keyCode === 87 || event.keyCode === 83) {
        keyPressed[event.keyCode] = false;
    }
}, false);
document.addEventListener('keydown', function(e) {
    var event = e || window.event;
    if(event.keyCode === 38 || event.keyCode === 40 || event.keyCode === 87 || event.keyCode === 83) {
        keyPressed[event.keyCode] = true;
    }
}, false);
Ball.reBuildBall();

/* ================================================================ */
/* 驱动动画函数 */
/* ================================================================ */
(function animate() {
    //绘制背景
    drawBackground(ctx);
    //绘制游戏区
    drawGameArea(ctx);
    //更新挡板位置
    updateBaffle();
    //绘制比分
    drawPoints(ctx);

    //处理p1,p2
    p1.draw(ctx);
    p2.draw(ctx);
    ball.update(ctx, p1, p2);

    stats.update();
    requestAnimationFrame(animate);
})();

//背景绘制函数
function drawBackground(ctx) {
    ctx.save();
    ctx.fillStyle = 'black';
    ctx.fillRect(0, 0, c.width, c.height);
    ctx.restore();
}

//游戏区绘制函数
function drawGameArea(ctx) {
    ctx.save();
    ctx.fillStyle = 'rgba(40, 40, 40, .75)';
    ctx.fillRect(gameAreaOffsetWidth, gameAreaOffsetHeight, gameAreaAbsoluteWidth, gameAreaAbsoluteHeight);
    ctx.fillStyle = '#666';
    ctx.fillRect(gameAreaOffsetWidth + gameAreaAbsoluteWidth / 2 - 4, gameAreaOffsetHeight, 8, gameAreaAbsoluteHeight);
    ctx.restore();
}

//绘制分数
function drawPoints(ctx) {
    var text = `${p1.points} : ${p2.points}`,
        textWidth;
    ctx.save();
    ctx.fillStyle = '#fff';
    ctx.font = '100px Arial';
    textWidth = ctx.measureText(text).width;
    ctx.fillText(text, c.width / 2 - textWidth / 2, gameAreaOffsetHeight + 100);
    ctx.restore();
}

//更新挡板位置函数
function updateBaffle() {
    if(keyPressed['38'] && keyPressed['40']) return;
    if(keyPressed['87'] && keyPressed['83']) return;
    if(keyPressed['38']) {
        p2.update(-1);
    }
    if(keyPressed['40']) {
        p2.update(1);
    }
    if(keyPressed['87']) {
        p1.update(-1);
    }
    if(keyPressed['83']) {
        p1.update(1);
    }
}